#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk, scrolledtext, messagebox
import threading
import queue
import time
from docx import Document

# 添加当前目录到Python路径，确保能导入merge_documents
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
try:
    from merge_documents import DocumentMerger
except ImportError:
    # 如果导入失败，提供一个简单的替代类
    class DocumentMerger:
        def get_docx_files(self, folder_path):
            docx_files = []
            for file in os.listdir(folder_path):
                if file.lower().endswith('.docx'):
                    docx_files.append(os.path.join(folder_path, file))
            return docx_files

class MergeDocumentsGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("文档编辑与合并工具")
        self.root.geometry("1200x800")
        self.root.minsize(1000, 600)
        
        # 设置中文字体
        self.font_config = {}
        try:
            # 尝试设置系统支持的中文字体
            self.font_config['normal'] = ('SimHei', 10)
            self.font_config['title'] = ('SimHei', 12, 'bold')
            self.font_config['text_editor'] = ('SimSun', 12)
            self.font_config['monospace'] = ('Consolas', 10)
        except:
            # 如果失败，使用默认字体
            self.font_config['normal'] = ('', 10)
            self.font_config['title'] = ('', 12, 'bold')
            self.font_config['text_editor'] = ('', 12)
            self.font_config['monospace'] = ('Courier', 10)
        
        # 初始化变量
        self.current_folder = None
        self.current_doc_path = None
        self.current_doc_content = {}
        self.selected_text = None
        self.docx_files = []
        
        # 创建UI
        self.create_widgets()
        
        # 绑定事件
        self.bind_events()
    
    def create_widgets(self):
        # 创建主框架，使用水平分隔
        main_frame = ttk.Frame(self.root, padding="0")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建顶部工具栏
        self.create_toolbar(main_frame)
        
        # 创建三栏布局框架
        content_frame = ttk.Frame(main_frame)
        content_frame.pack(fill=tk.BOTH, expand=True, pady=(5, 0))
        
        # 左侧导航栏 - 文档列表
        self.create_left_navigation(content_frame)
        
        # 中间编辑区
        self.create_center_editor(content_frame)
        
        # 右侧对话修改区
        self.create_right_dialog(content_frame)
        
        # 创建状态栏
        self.create_status_bar(main_frame)
    
    def create_toolbar(self, parent):
        toolbar = ttk.Frame(parent, padding="5")
        toolbar.pack(fill=tk.X, side=tk.TOP)
        
        # 打开文件夹按钮
        ttk.Button(toolbar, text="打开文件夹", command=self.open_folder).pack(side=tk.LEFT, padx=5)
        
        # 保存当前文档按钮
        self.save_button = ttk.Button(toolbar, text="保存文档", command=self.save_current_document, state=tk.DISABLED)
        self.save_button.pack(side=tk.LEFT, padx=5)
        
        # 合并文档按钮
        self.merge_button = ttk.Button(toolbar, text="合并文档", command=self.merge_documents, state=tk.DISABLED)
        self.merge_button.pack(side=tk.LEFT, padx=5)
        
        # 分隔符
        ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=10, fill=tk.Y)
        
        # 当前文件夹显示
        self.folder_label = ttk.Label(toolbar, text="未选择文件夹", font=self.font_config['normal'])
        self.folder_label.pack(side=tk.LEFT, padx=10, fill=tk.X, expand=True)
    
    def create_left_navigation(self, parent):
        # 左侧导航栏容器
        left_frame = ttk.LabelFrame(parent, text="文档导航", padding="5")
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=(5, 2), pady=5, ipady=5, ipadx=5)
        left_frame.config(width=250)
        
        # 文档列表
        self.doc_listbox = tk.Listbox(
            left_frame,
            font=self.font_config['normal'],
            selectmode=tk.SINGLE,
            activestyle='dotbox'
        )
        
        # 垂直滚动条
        y_scrollbar = ttk.Scrollbar(
            left_frame,
            orient=tk.VERTICAL,
            command=self.doc_listbox.yview
        )
        self.doc_listbox.config(yscrollcommand=y_scrollbar.set)
        
        # 水平滚动条
        x_scrollbar = ttk.Scrollbar(
            left_frame,
            orient=tk.HORIZONTAL,
            command=self.doc_listbox.xview
        )
        self.doc_listbox.config(xscrollcommand=x_scrollbar.set)
        
        # 布局
        y_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        x_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
        self.doc_listbox.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
    
    def create_center_editor(self, parent):
        # 中间编辑区容器
        center_frame = ttk.LabelFrame(parent, text="文档内容编辑", padding="5")
        center_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=5, ipady=5, ipadx=5)
        
        # 文档内容编辑器
        self.content_text = scrolledtext.ScrolledText(
            center_frame,
            font=self.font_config['text_editor'],
            wrap=tk.WORD,
            undo=True,
            maxundo=-1
        )
        self.content_text.pack(fill=tk.BOTH, expand=True)
        
        # 初始状态禁用
        self.content_text.config(state=tk.DISABLED)
        
        # 底部信息栏
        info_frame = ttk.Frame(center_frame)
        info_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=(5, 0))
        
        self.word_count_label = ttk.Label(info_frame, text="字数: 0", font=self.font_config['normal'])
        self.word_count_label.pack(side=tk.LEFT, padx=5)
        
        self.selection_info_label = ttk.Label(info_frame, text="选中: 0 字符", font=self.font_config['normal'])
        self.selection_info_label.pack(side=tk.LEFT, padx=5)
    
    def create_right_dialog(self, parent):
        # 右侧对话修改区容器
        right_frame = ttk.LabelFrame(parent, text="内容修改区域", padding="5")
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=False, padx=(2, 5), pady=5, ipady=5, ipadx=5)
        right_frame.config(width=350)
        
        # 选中内容显示框
        ttk.Label(right_frame, text="当前选中内容:", font=self.font_config['normal']).pack(anchor=tk.W, pady=(0, 2))
        self.selected_text_view = scrolledtext.ScrolledText(
            right_frame,
            font=self.font_config['monospace'],
            wrap=tk.WORD,
            height=6
        )
        self.selected_text_view.pack(fill=tk.X, pady=(0, 5))
        self.selected_text_view.config(state=tk.DISABLED)
        
        # 分隔线
        ttk.Separator(right_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=5)
        
        # 修改内容输入框
        ttk.Label(right_frame, text="修改后的内容:", font=self.font_config['normal']).pack(anchor=tk.W, pady=(0, 2))
        self.modified_text_input = scrolledtext.ScrolledText(
            right_frame,
            font=self.font_config['monospace'],
            wrap=tk.WORD,
            height=10
        )
        self.modified_text_input.pack(fill=tk.X, pady=(0, 5))
        self.modified_text_input.config(state=tk.DISABLED)
        
        # 操作按钮
        button_frame = ttk.Frame(right_frame)
        button_frame.pack(fill=tk.X, pady=5)
        
        self.update_button = ttk.Button(
            button_frame,
            text="更新到文档",
            command=self.update_selected_text,
            state=tk.DISABLED
        )
        self.update_button.pack(side=tk.LEFT, padx=5)
        
        self.copy_to_dialog_button = ttk.Button(
            button_frame,
            text="复制选中到修改区",
            command=self.copy_selected_to_dialog,
            state=tk.DISABLED
        )
        self.copy_to_dialog_button.pack(side=tk.LEFT, padx=5)
    
    def create_status_bar(self, parent):
        status_bar = ttk.Frame(parent, height=24, relief=tk.SUNKEN)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        self.status_label = ttk.Label(status_bar, text="就绪", font=self.font_config['normal'], anchor=tk.W, padding=(5, 2))
        self.status_label.pack(fill=tk.X)
    
    def bind_events(self):
        # 绑定文档列表点击事件
        self.doc_listbox.bind('<<ListboxSelect>>', self.on_document_select)
        
        # 绑定文本框选择事件
        self.content_text.bind('<<Selection>>', self.on_text_selection)
        
        # 绑定文本修改事件，用于字数统计
        self.content_text.bind('<KeyRelease>', self.update_word_count)
        
        # 绑定复制到修改区按钮的状态更新
        self.content_text.bind('<ButtonRelease-1>', lambda event: self.update_copy_button_state())
    
    def open_folder(self):
        """打开文件夹并列出Word文档"""
        folder = filedialog.askdirectory(title="选择包含Word文档的文件夹")
        if folder:
            self.current_folder = folder
            self.folder_label.config(text=folder)
            self.status_label.config(text=f"已打开文件夹: {os.path.basename(folder)}")
            
            # 列出Word文档
            self.list_docx_files(folder)
            
            # 启用合并按钮
            if len(self.docx_files) > 0:
                self.merge_button.config(state=tk.NORMAL)
            else:
                self.merge_button.config(state=tk.DISABLED)
    
    def list_docx_files(self, folder_path):
        """列出指定文件夹中的Word文档"""
        self.doc_listbox.delete(0, tk.END)
        self.docx_files = []
        
        try:
            merger = DocumentMerger()
            self.docx_files = merger.get_docx_files(folder_path)
            
            if not self.docx_files:
                self.status_label.config(text="未检测到Word文档(.docx)")
                return
            
            for file_path in self.docx_files:
                # 只显示文件名，不显示完整路径
                file_name = os.path.basename(file_path)
                self.doc_listbox.insert(tk.END, file_name)
            
            self.status_label.config(text=f"找到 {len(self.docx_files)} 个Word文档")
        except Exception as e:
            self.status_label.config(text=f"列出文档失败: {str(e)}")
            messagebox.showerror("错误", f"列出文档失败: {str(e)}")
    
    def on_document_select(self, event):
        """当选择文档时，读取并显示其内容"""
        selection = self.doc_listbox.curselection()
        if not selection:
            return
        
        # 获取选中的文档索引
        index = selection[0]
        if index >= len(self.docx_files):
            return
        
        # 获取文档路径
        doc_path = self.docx_files[index]
        self.current_doc_path = doc_path
        
        # 更新状态
        self.status_label.config(text=f"正在打开文档: {os.path.basename(doc_path)}")
        
        # 在新线程中读取文档内容，避免UI阻塞
        threading.Thread(target=self.load_document_content, args=(doc_path,)).start()
    
    def load_document_content(self, doc_path):
        """读取Word文档内容"""
        try:
            # 使用python-docx读取文档
            doc = Document(doc_path)
            content = []
            
            # 提取文档内容
            for para in doc.paragraphs:
                content.append(para.text)
            
            # 将内容更新到UI（在主线程中执行）
            full_text = "\n".join(content)
            self.root.after(0, lambda text=full_text: self.display_document_content(text))
            
            # 保存当前文档内容
            self.current_doc_content = {
                'path': doc_path,
                'content': full_text,
                'paragraphs': [para.text for para in doc.paragraphs]
            }
            
        except Exception as e:
            error_msg = f"读取文档失败: {str(e)}"
            self.root.after(0, lambda: self.status_label.config(text=error_msg))
            self.root.after(0, lambda: messagebox.showerror("错误", error_msg))
    
    def display_document_content(self, content):
        """在编辑区显示文档内容"""
        # 清空并启用编辑区
        self.content_text.config(state=tk.NORMAL)
        self.content_text.delete(1.0, tk.END)
        self.content_text.insert(tk.END, content)
        self.content_text.config(state=tk.NORMAL)  # 保持可编辑
        
        # 更新字数统计
        self.update_word_count()
        
        # 启用保存按钮
        self.save_button.config(state=tk.NORMAL)
        
        # 更新状态
        self.status_label.config(text=f"已打开: {os.path.basename(self.current_doc_path)}")
    
    def save_current_document(self):
        """保存当前编辑的文档"""
        if not self.current_doc_path:
            return
        
        try:
            # 获取编辑区的内容
            edited_content = self.content_text.get(1.0, tk.END).strip()
            
            # 创建新文档
            doc = Document()
            
            # 按行分割内容并添加为段落
            paragraphs = edited_content.split('\n')
            for para_text in paragraphs:
                doc.add_paragraph(para_text)
            
            # 保存文档
            doc.save(self.current_doc_path)
            
            # 更新状态
            self.status_label.config(text=f"已保存: {os.path.basename(self.current_doc_path)}")
            
            # 可选：显示保存成功提示
            messagebox.showinfo("成功", f"文档已成功保存: {os.path.basename(self.current_doc_path)}")
            
        except Exception as e:
            error_msg = f"保存文档失败: {str(e)}"
            self.status_label.config(text=error_msg)
            messagebox.showerror("错误", error_msg)
    
    def merge_documents(self):
        """合并选定文件夹中的所有Word文档"""
        if not self.current_folder or len(self.docx_files) == 0:
            messagebox.showwarning("警告", "请先选择包含Word文档的文件夹")
            return
        
        # 询问保存位置
        output_file = filedialog.asksaveasfilename(
            title="保存合并后的文档",
            defaultextension=".docx",
            filetypes=[("Word文档", "*.docx"), ("所有文件", "*.*")],
            initialfile="合并文档.docx"
        )
        
        if not output_file:
            return
        
        # 更新状态
        self.status_label.config(text="正在合并文档...")
        
        # 在新线程中执行合并，避免UI阻塞
        threading.Thread(
            target=self.do_merge_documents,
            args=(self.current_folder, output_file)
        ).start()
    
    def do_merge_documents(self, folder_path, output_path):
        """执行文档合并操作"""
        try:
            # 创建新文档作为合并结果
            merged_doc = Document()
            merged_doc.add_heading('合并文档', level=0)
            
            total_docs = len(self.docx_files)
            
            for i, doc_path in enumerate(self.docx_files):
                # 更新状态
                doc_name = os.path.basename(doc_path)
                self.root.after(0, lambda name=doc_name: 
                                self.status_label.config(text=f"合并中 {i+1}/{total_docs}: {name}"))
                
                # 添加文档分隔信息
                merged_doc.add_page_break()
                merged_doc.add_heading(f"文档: {doc_name}", level=1)
                
                # 打开源文档并复制内容
                try:
                    source_doc = Document(doc_path)
                    
                    # 复制段落
                    for para in source_doc.paragraphs:
                        # 跳过空段落
                        if para.text.strip():
                            merged_doc.add_paragraph(para.text)
                    
                    # 复制表格（简单实现，不保留格式）
                    for table in source_doc.tables:
                        # 添加表格标记
                        merged_doc.add_paragraph("[表格内容]")
                        # 简单地将表格内容转换为文本
                        for row in table.rows:
                            row_text = " | ".join(cell.text.strip() for cell in row.cells)
                            merged_doc.add_paragraph(row_text)
                except Exception as e:
                    # 如果单个文档处理失败，记录错误但继续处理其他文档
                    error_msg = f"处理文档 {doc_name} 失败: {str(e)}"
                    self.root.after(0, lambda msg=error_msg: self.status_label.config(text=msg))
                    merged_doc.add_paragraph(f"[错误: {error_msg}]")
            
            # 保存合并后的文档
            merged_doc.save(output_path)
            
            # 更新状态
            success_msg = f"文档合并完成: {os.path.basename(output_path)}"
            self.root.after(0, lambda msg=success_msg: self.status_label.config(text=msg))
            self.root.after(0, lambda: messagebox.showinfo("成功", success_msg))
            
        except Exception as e:
            error_msg = f"合并文档失败: {str(e)}"
            self.root.after(0, lambda msg=error_msg: self.status_label.config(text=msg))
            self.root.after(0, lambda: messagebox.showerror("错误", error_msg))
    
    def on_text_selection(self, event):
        """当在编辑区选择文本时更新选择信息"""
        self.update_selection_info()
        self.update_copy_button_state()
    
    def update_word_count(self, event=None):
        """更新字数统计"""
        text = self.content_text.get(1.0, tk.END).strip()
        char_count = len(text)
        word_count = len(text.split()) if text else 0
        self.word_count_label.config(text=f"字数: {char_count} | 词数: {word_count}")
    
    def update_selection_info(self):
        """更新选中文本信息"""
        try:
            start_index = self.content_text.index(tk.SEL_FIRST)
            end_index = self.content_text.index(tk.SEL_LAST)
            # 计算选中的字符数
            start_pos = self.content_text.index(start_index).split('.')
            end_pos = self.content_text.index(end_index).split('.')
            
            # 简单的字符数计算（不完全准确，但足够使用）
            lines_diff = int(end_pos[0]) - int(start_pos[0])
            chars_diff = int(end_pos[1]) - int(start_pos[1])
            char_count = chars_diff if lines_diff == 0 else (lines_diff * 80) + chars_diff  # 粗略估计
            
            self.selection_info_label.config(text=f"选中: {char_count} 字符")
        except tk.TclError:
            # 没有选中的文本
            self.selection_info_label.config(text="选中: 0 字符")
    
    def update_copy_button_state(self):
        """更新复制按钮状态"""
        try:
            # 尝试获取选中的文本，如果失败说明没有选中
            self.content_text.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.copy_to_dialog_button.config(state=tk.NORMAL)
        except tk.TclError:
            self.copy_to_dialog_button.config(state=tk.DISABLED)
    
    def copy_selected_to_dialog(self):
        """复制选中的文本到修改区"""
        try:
            # 获取选中的文本
            self.selected_text = self.content_text.get(tk.SEL_FIRST, tk.SEL_LAST)
            
            # 在选中内容显示框中显示
            self.selected_text_view.config(state=tk.NORMAL)
            self.selected_text_view.delete(1.0, tk.END)
            self.selected_text_view.insert(tk.END, self.selected_text)
            self.selected_text_view.config(state=tk.DISABLED)
            
            # 在修改内容输入框中显示选中的文本，供用户修改
            self.modified_text_input.config(state=tk.NORMAL)
            self.modified_text_input.delete(1.0, tk.END)
            self.modified_text_input.insert(tk.END, self.selected_text)
            self.modified_text_input.config(state=tk.NORMAL)  # 保持可编辑
            
            # 启用更新按钮
            self.update_button.config(state=tk.NORMAL)
            
            # 更新状态
            self.status_label.config(text="已复制选中内容到修改区")
            
        except tk.TclError:
            # 没有选中的文本
            self.status_label.config(text="请先选择要修改的文本")
    
    def update_selected_text(self):
        """将修改后的内容更新到文档中"""
        if not self.selected_text:
            messagebox.showwarning("警告", "请先复制文本到修改区")
            return
        
        try:
            # 获取修改后的内容
            modified_text = self.modified_text_input.get(1.0, tk.END).strip()
            
            # 尝试替换选中的文本
            self.content_text.delete(tk.SEL_FIRST, tk.SEL_LAST)
            self.content_text.insert(tk.SEL_FIRST, modified_text)
            
            # 更新字数统计
            self.update_word_count()
            
            # 更新状态
            self.status_label.config(text="已将修改后的内容更新到文档")
            
            # 清空修改区
            self.modified_text_input.delete(1.0, tk.END)
            self.selected_text_view.config(state=tk.NORMAL)
            self.selected_text_view.delete(1.0, tk.END)
            self.selected_text_view.config(state=tk.DISABLED)
            
            # 禁用更新按钮
            self.update_button.config(state=tk.DISABLED)
            
        except tk.TclError:
            # 选中区域可能已经改变
            messagebox.showwarning("警告", "无法更新文本，请重新选择要替换的内容")
    
    def close_app(self):
        """关闭应用程序"""
        # 检查是否有未保存的更改
        if self.save_button.cget('state') == tk.NORMAL:
            if messagebox.askyesnocancel("确认退出", "当前文档可能有未保存的更改，是否保存？\n是 - 保存并退出\n否 - 不保存直接退出\n取消 - 取消操作") is None:
                return  # 用户点击取消
            elif messagebox.askyesnocancel("确认退出", "当前文档可能有未保存的更改，是否保存？"):
                self.save_current_document()
        
        # 关闭应用
        self.root.destroy()

if __name__ == "__main__":
    # 确保中文显示正常
    if sys.platform == 'win32':
        # Windows系统下设置默认字体
        import ctypes
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    
    root = tk.Tk()
    app = MergeDocumentsGUI(root)
    
    # 设置窗口关闭事件处理
    root.protocol("WM_DELETE_WINDOW", app.close_app)
    
    # 启动主循环
    root.mainloop()